#include "MusicList.h"


/***
		Constructors
								***/

MusicList::MusicList(QObject* parent) : QObject(parent)
{
	mode=0;
	position=-1;
}


/***
		Getters + setters
											***/

int MusicList::getPosition()
{
	return position;
}

int MusicList::getMode()
{
	return mode;
}

/***
		Operations on the playlists
																***/

void MusicList::add(Track* track, bool resolved)
{
	list.append(track);
	if(!resolved)
	{
		track->resolve();
		connect(track, SIGNAL(metaDataResolved(int)), this, SLOT(onTrackMetaDataResolved(int)));
	}
	else
	{
		emit(dataAdded());
	}
}

void MusicList::remove(int id)
{
	if(id>=0&&id<list.size())
	{
		list.remove(id);
	}
}

void MusicList::remove(Track* track)
{
	if(list.contains(track))
	{
		int position=list.indexOf(track);
		delete track;
		remove(position);
	}
}

void MusicList::setMode(int mode)
{
	if(mode>=0&&mode<=3)
	{
		this->mode=mode;
	}
}

/***
		Navigation in the playlists
																***/

Track* MusicList::previous()
{

	qDebug() << lastPlayedList.size();
	if(lastPlayedList.size()>0)
	{
		Track* lastPlayedTrack=lastPlayedList.last();
		position=list.indexOf(lastPlayedTrack);
		lastPlayedList.pop_back();
		return lastPlayedTrack;
	}
	return NULL;
		
}

Track* MusicList::next()
{
	if(list.size()>0)
	{
		if(mode==0||mode==2)
		{
			if(position==-1)
			{
				position=0;
				return list.at(position);
			}
			else
			{
				lastPlayedList.append(list.at(position));
				if(position>=0&&position<list.size()-1)
				{
					position++;
					return list.at(position);
				}
				else if(position==list.size()-1)
				{
					if(mode==2)
					{
						position=0;
						return list.at(position);
					}
					else
					{
						return NULL;
					}
				}
				return NULL;
			}
		}
		else if(mode==1||mode==3)
		{
			if(position!=-1)
			{
				lastPlayedList.append(list.at(position));
			}
			position=getRandomNumber(0, list.size()-1);
			return list.at(position);
		}
		else
		{
			return NULL;
		}
	}
	else
	{
		return NULL;
	}
		
}

Track* MusicList::first()
{
	if(list.size()>0)
	{
		if(position>=0&&position<=list.size())
		{
			lastPlayedList.append(list.at(position));
		}
		position=0;
		return list.at(position);
	}
	else
	{
		return NULL;
	}
}

Track* MusicList::last()
{
	if(list.size()>0)
	{
		if(position>=0&&position<=list.size())
		{
			lastPlayedList.append(list.at(position));
		}
		position=list.size()-1;
		return list.at(position);
	}
	else
	{
		return NULL;
	}
}
int MusicList::size()
{
	return list.size();
}

Track* MusicList::seek(int index)
{
	if(list.size()>0)
	{
		if(index>=0&&index<list.size())
		{
			if(position!=-1)
			{
				lastPlayedList.append(list.at(position));
			}
			position=index;
			return list.at(position);
		}
		else
		{
			return NULL;
		}
	}
	else
	{
		return NULL;
	}
}


/***
		Operators overloadings
													***/

Track* MusicList::operator[](int index)
{
	if(index>=0&&index<list.size())
	{
		return list.at(index);
	}
	else
	{
		return NULL;
	}
}


/***
                Import/Export to M3U and PLS
                                                                                                                ***/

//Export of the playlist to the M3U format
void MusicList::saveToM3U(QString& playlistPath)
{
    QString buffer;
    int nbElements = list.size();
    int i;
    
    
    buffer = "#EXTM3U";
    buffer += '\n';
    
    for(i = 0;i < nbElements;i++)
    {
        buffer += '\n';
        buffer += "#EXTINF:";
        
        // Convert length from integer to QString and appends it to the end of buffer :
        buffer += QString::number(list[i]->getLength());
        
        buffer += ',';
        
        buffer += list[i]->getTitle();
        
        buffer += '\n';
        
        buffer += list[i]->getPath();
        
        buffer += '\n';
    }
    
    FILE* fd = fopen(playlistPath.toStdString().data(),"w");
    if(fd == NULL) { perror("fopen "); }
    fprintf(fd,buffer.toStdString().data());
    fclose(fd);
}

//Export of the playlist to the PLS format
void MusicList::saveToPLS(QString& playlistPath)
{
    QString buffer;
    int nbElements = list.size();
    int i;
    
    
    buffer = "[playlist]";
    buffer += '\n';
    buffer += '\n';
    
    for(i = 0;i < nbElements;i++)
    {
        buffer += "File";
        char chaineNoElement[10];
        buffer += QString::number(i+1);
        buffer += '=';
        
        buffer += list[i]->getPath();
        buffer += '\n';
        
        
        buffer += "Title";
        buffer += chaineNoElement;
        buffer += '=';
        
        buffer += list[i]->getTitle();
        buffer += '\n';
        
        
        buffer += "Length";
        buffer += chaineNoElement;
        buffer += '=';
        
        buffer += QString::number(list[i]->getLength());
        buffer += '\n';
        buffer += '\n';
    }
    
    buffer += "NumberOfEntries=";
    buffer += QString::number(nbElements);
    buffer += '\n';
    buffer += '\n';
    
    buffer += "Version=2";
    buffer += '\n';
    
    FILE* fd = fopen(playlistPath.toStdString().data(),"w");
    if(fd == NULL) { perror("fopen "); }
    fprintf(fd,buffer.toStdString().data());
    fclose(fd);
}

//Import of the playlist from the M3U format
void MusicList::loadFromM3U(QString& playlistPath)
{
    char buffer[1024];
    
    list.clear();
    
    FILE* fd = fopen(playlistPath.toStdString().data(),"r");
    if(fd == NULL) { perror("fopen "); }
    
    fgets(buffer,1024,fd);
    if(strcmp(buffer,"#EXTM3U\n") == 0)
    {
        fgets(buffer,1024,fd);
        while(feof(fd) == 0)
        {
            if(strstr(buffer,"#EXTINF:") != NULL) //if the current line contains "#EXTINF:"
            {
                fgets(buffer,1024,fd);
                buffer[strlen(buffer) - 1] = '\0';
                
                QString pathNewTrack = buffer;
                Track* newTrack = new Track(pathNewTrack);
                this->add(newTrack);
            }
            
            fgets(buffer,1024,fd);
        }
    }
    
    fclose(fd);
}

//Import of the playlist to the PLS format
void MusicList::loadFromPLS(QString& playlistPath)
{
    char buffer[1024];
    int i;
    
    list.clear();
    
    FILE* fd = fopen(playlistPath.toStdString().data(),"r");
    if(fd == NULL) { perror("fopen "); }
    
    fgets(buffer,1024,fd);
    if(strcmp(buffer,"[playlist]\n") == 0)
    {
        fgets(buffer,1024,fd);
        while(feof(fd) == 0)
        {
            if(strstr(buffer,"File") == buffer) //if the current line contains a "File" string at the beginning of the line 
            {
                buffer[strlen(buffer) - 1] = '\0';
                for(i = 0;buffer[i] != '=';i++);
                
                QString pathNewTrack = buffer + i + 1;
                Track *newTrack = new Track(pathNewTrack);
                this->add(newTrack);
            }
            
            fgets(buffer,1024,fd);
        }
    }
    
    fclose(fd);
}

void MusicList::saveToXML()
{
	QString filename = "niaapdb.xml";
	QFile file(filename);
	// Ouverture du fichier en écriture et en texte.
	file.open(QFile::WriteOnly | QFile::Text | QFile::Truncate);
	QXmlStreamWriter writer(&file);
	
	// Permet l'indentation du fichier XML
	writer.setAutoFormatting(true);

	// Écrit l'en-tête du fichier XML : <?xml version="1.0" encoding="UTF-8" ?> 
	writer.writeStartDocument();
	
	// Élément racine du fichier XML
	writer.writeStartElement("niaapdb");
		writer.writeAttribute("version", "0.1");
	for(int i=0;i<list.size();i++)
	{
			writer.writeStartElement("entry");
				writer.writeAttribute("type", "song");
					writer.writeTextElement("path", list[i]->getPath());
					writer.writeTextElement("artist", list[i]->getArtist());
					writer.writeTextElement("album", list[i]->getAlbum());
					writer.writeTextElement("genre", list[i]->getGenre());
					writer.writeTextElement("track-number", QString::number(list[i]->getTrackNumber()));
					writer.writeTextElement("length", QString::number(list[i]->getLength()));
					writer.writeTextElement("title", list[i]->getTitle());
			writer.writeEndElement();
	}
	// Finalise le document XML
	writer.writeEndDocument();

	// Fermer le fichier pour bien enregistrer le document et ferme l'élément niaapdb
	file.close();
}

void MusicList::loadFromXML()
{
	QXmlStreamReader reader; // Objet servant à la navigation
	QString filename = "niaapdb.xml";
	QFile file(filename);
	if(file.open(QFile::ReadOnly | QFile::Text)) // Ouverture du fichier XML en lecture seule et en mode texte
	{
		reader.setDevice(&file); // Initialise l'instance reader avec le flux XML venant de file
		Track* track;
		list.clear();
		 
		//Le but de cette boucle est de parcourir le fichier et de vérifier si l'on est au début d'un élément.
		reader.readNext();
		while (!reader.atEnd())
		{
		    if (reader.isStartElement()) 
		    {
			if (reader.name() == "niaapdb") 
			{
			    reader.readNext(); // On va au prochain token
			    // Tant que celui-ci n'est pas un élément de départ on avance au token suivant
			    while(reader.isStartElement()==false)
				reader.readNext();
		
			    while(reader.name() == "entry")
			    {
				
				track=new Track();
				qDebug() << "new entry: " << track->getId();
				reader.readNext();
				while(reader.isStartElement()==false)
				reader.readNext();
				if(reader.name() == "path")
				{
				    qDebug()<<"track " << track->getId() << "step 1";
				    track->setPath(reader.readElementText());
				    reader.readNext();
				    while(reader.isStartElement()==false)
				    reader.readNext();
				}
				if(reader.name() == "artist")
				{
				    qDebug()<<"track " << track->getId() << "step 2";
				    track->setArtist(reader.readElementText());
				    reader.readNext();
				    while(reader.isStartElement()==false)
				    reader.readNext();
				}
				if(reader.name() == "album")
				{
				    qDebug()<<"track " << track->getId() << "step 3";
				    track->setAlbum(reader.readElementText());
				    reader.readNext();
				    while(reader.isStartElement()==false)
				    reader.readNext();
				}
				if(reader.name() == "genre")
				{
				    qDebug()<<"track " << track->getId() << "step 4";
				    track->setGenre(reader.readElementText());
				    reader.readNext();
				    while(reader.isStartElement()==false)
				    reader.readNext();
				}
				if(reader.name() == "track-number")
				{
				    qDebug()<<"track " << track->getId() << "step 5";
				    track->setTrackNumber(reader.readElementText().toInt());
				    reader.readNext();
				    while(reader.isStartElement()==false)
				    reader.readNext();
				}
				if(reader.name() == "length")
				{
				    qDebug()<<"track " << track->getId() << "step 6";
				    track->setLength(reader.readElementText().toLongLong());
				    reader.readNext();
				    while(reader.isStartElement()==false)
				    reader.readNext();
				}
				if(reader.name() == "title")
				{
				    qDebug()<<"track " << track->getId() << "step 7";
				    track->setTitle(reader.readElementText());
				    track->setResolved(true);
				    this->add(track, true);
				    
				    reader.readNext();
				    while(reader.isStartElement()==false&&reader.atEnd()==false)
				    {
				    	qDebug() << reader.name();
				    	if(reader.isEndElement())
				    	{
				    		if(reader.name()=="niaapdb")
				    		{
				    			break;
				    		}
				    	}
				    	reader.readNext();
				    }
				    	
				    
				}
			     
			    }
			}
		    }
		    reader.readNext(); // On va au prochain token
		}
		file.close();
	}
}






/***
		Slots
						***/

void MusicList::onTrackMetaDataResolved(int trackId)
{
	qDebug() << "yhj";
	for(int i=0;i<list.size();i++)
	{
		if(list.at(i)->getId()==trackId)
		{
			emit(dataChange(i));
			return;
		}
	}
}	

int MusicList::getRandomNumber(int min, int max)
{
	QTime midnight(0, 0, 0);
	qsrand(midnight.secsTo(QTime::currentTime()));	
	return min+qrand()%(max+1);
}
